package com.smsc.headend.connector.bo;

import cn.hutool.core.date.SystemClock;
import com.smsc.headend.connector.exception.UDISDeviceConException;
import gurux.dlms.GXDLMSClient;
import gurux.dlms.GXReplyData;
import lombok.Data;
import lombok.experimental.Accessors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.time.DateUtils;

import java.util.Deque;
import java.util.LinkedList;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

@Data
@Slf4j
@Accessors(chain = true)
public class TaskContext {
    Long comId;

    Long meterId;

    String deviceAddress;

    GXDLMSClient client;

    GXReplyData notify;

    //单个任务的属性
    String taskNo;

    String atomicTaskNo;

    volatile AtomicInteger invokeId;

    Boolean returnPacket;
    /**
     * 同atomicTaskNo， 只保留最新的。 意义同  {@See com.smsc.headend.module.task.dto.ConnectorTask#flag}
     */
    int flag;

    // 46上一帧的frameId
    short lastFrameId;

    Map<Integer, String> invokeIdAtomicTaskNoMap = new ConcurrentHashMap();
    Map<Integer, Long> taskNoTimeStampMap = new ConcurrentHashMap();

    /**
     * 从TaskEngine 传输过来待发送的通讯包
     */
    Map<String,  Deque<FramePacket>> atomicTaskNoPacketDequeMap = new ConcurrentHashMap();

    public void refresh(String atomicTaskNo) {
        this.notify = null;
        this.atomicTaskNoPacketDequeMap.remove(atomicTaskNo);
        Map.Entry<Integer, String> m =  this.invokeIdAtomicTaskNoMap.entrySet().stream().filter(e -> e.getValue().equals(atomicTaskNo)).findAny().orElse(null);
        if (m != null) {
            this.removeInvokeId(m.getKey());
        }
        //重置client对象里面的block信息
        try {
            if (this.client != null) {
                this.client.getObjectsRequest();
            }
        } catch (Exception e) {
            log.error("refresh client error", e);
        }
    }

    public void addInvokeIdAndAtomicTaskNo(Integer invokeId, String atomicTaskNo) throws UDISDeviceConException {
        if (invokeIdAtomicTaskNoMap.containsKey(invokeId)) {
            Long insertTime = taskNoTimeStampMap.get(invokeId);
            if (insertTime != null && SystemClock.now() - insertTime <= 2 * DateUtils.MILLIS_PER_MINUTE) {
                throw new UDISDeviceConException("InvokeId have task processing");
            }
        }
        invokeIdAtomicTaskNoMap.put(invokeId, atomicTaskNo);
        taskNoTimeStampMap.put(invokeId, SystemClock.now());
    }

    public void removeInvokeId(Integer invokeId) {
        invokeIdAtomicTaskNoMap.remove(invokeId);
        taskNoTimeStampMap.remove(invokeId);
    }

    public String getAtomicTaskNoByInvokeId(Integer invokeId) {
        return invokeIdAtomicTaskNoMap.get(invokeId);
    }

    public Deque<FramePacket> getSendQueueByAtomicTaskNo(String atomicTaskNo) {
        return atomicTaskNoPacketDequeMap.get(atomicTaskNo);
    }

    public void addTaskPacketQueue(String atomicTaskNo, LinkedList<FramePacket> linkedList) {
        atomicTaskNoPacketDequeMap.put(atomicTaskNo, linkedList);
    }
}
